﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace Game_Project
{
    class NodeGameLogic
    {
        private readonly GameField gameField;
        private readonly Drawer drawer;
        private readonly Random rnd;
        private List<ConsoleNode> nodes;
        private ConsoleNode target;
        private int[] winCounts;
        private int nodeCount;
        private readonly InputHandler _ih;
        public MoveDirectionNode dir = MoveDirectionNode.Up;


        public NodeGameLogic(GameField gameField, Drawer drawer, int nodeCount, InputHandler ih)
        {
            this.gameField = gameField;
            this.drawer = drawer;
            this.nodeCount = nodeCount;

            _ih = ih;
            _ih.KeyLeft += MoveNodeLeft;
            _ih.KeyRight += MoveNodeRight;
            _ih.KeyUp += MoveNodeUp;
            _ih.KeyDown += MoveNodeDown;


            rnd = new Random();
            nodes = new List<ConsoleNode>();
            target = GenerateRandomTarget('@', ConsoleColor.White);

        }


        public void StartGame()
        {
            //bool isGameOver = false;
            for (int z = 0; z < 1000; z++)
            {
                nodes = new List<ConsoleNode>()
                {
                    new ConsoleNode(0,0,'@', ConsoleColor.Green),
                    new ConsoleNode(0,0,'X', ConsoleColor.Blue)

                };
                if (winCounts == null)
                    winCounts = new int[nodes.Count];
                RandomPlacement(nodes);
                Console.Clear();
                drawer.DrawListAndScore(nodes, gameField, 5, winCounts);
                bool isNewRound = false;
                do
                {
                    drawer.DrawGameField(gameField, '0');
                    drawer.DrawNodeList(nodes);
                    drawer.DrawNode(target);
                    _ih.QueryKB();
                    nodes[1].Move(CheckPosition);
                    for (int i = 0; i < nodes.Count; i++)
                    {
                        if (IsNodeOnTarget(nodes[i]))
                        {
                            winCounts[i]++;
                            isNewRound = true;
                            target = GenerateRandomTarget((char)1, ConsoleColor.White);
                        }
                    }
                    //drawer.DrawNodeList(nodes);
                    //drawer.DrawNode(target);
                    Thread.Sleep(50);
                }
                while (!isNewRound);

                //Console.ReadKey();

            }
            Console.ReadKey();
        }


        public void SnakeGame()
        {
            bool isGameOver = false;
            nodes = new List<ConsoleNode>()
            {
                new ConsoleNode((gameField.X + gameField.Width)/2, (gameField.Y+gameField.Height)/2, '@', ConsoleColor.Green)
            };

            nodes.Add(new ConsoleNode(nodes[0].X, nodes[0].Y + 1, '*', ConsoleColor.White));
            nodes.Add(new ConsoleNode(nodes[0].X, nodes[0].Y + 2, '*', ConsoleColor.White));

            do
            {
                Console.Clear();
                bool isNewRound = false;

                do
                {
                    drawer.DrawGameField(gameField, '0');
                    drawer.DrawNodeList(nodes);
                    drawer.DrawNode(target);

                    
                    
                    SnakeListMove(nodes);
                    ConstantMove(nodes[0], CheckPosition, dir);
                    _ih.QueryKB();

                    //Thread.Sleep(150);


                    for (int i = 0; i < nodes.Count; i++)
                    {
                        if (IsNodeOnTarget(nodes[i]))
                        {
                            nodes.Add(new ConsoleNode(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y, '*', ConsoleColor.White));
                            target = GenerateRandomTarget('@', ConsoleColor.White);
                            isNewRound = true;
                        }
                        //else()
                        //isGameOver = true;
                    }
                    Thread.Sleep(150);


                }
                while (!isNewRound);
            } while (!isGameOver);
        }


        private ConsoleNode GenerateRandomNode(int nodeCount)
        {

            int randomX = 0;
            int randomY = 0;
            do
            {
                randomX = rnd.Next(gameField.X, gameField.Width + gameField.X);
                randomY = rnd.Next(gameField.Y, gameField.Height + gameField.Y);

            } while (!IsPositionFree(randomX, randomY));

            return new ConsoleNode(randomX, randomY, (char)(nodeCount + 41),
                                        (ConsoleColor)rnd.Next(1, 15));
        }

        private ConsoleNode GenerateRandomTarget(char symbol, ConsoleColor color)
        {

            int randomX = 0;
            int randomY = 0;
            do
            {
                randomX = rnd.Next(gameField.X, gameField.Width + gameField.X);
                randomY = rnd.Next(gameField.Y, gameField.Height + gameField.Y);

            } while (!IsPositionFree(randomX, randomY));

            return new ConsoleNode(randomX, randomY, symbol, color);
        }

        private void GenerateRandomNodes()

        {
            for (int i = 0; i < nodeCount; i++)
            {
                nodes.Add(GenerateRandomNode(i));
            }
        }

        private bool IsPositionFree(int x, int y)
        {
            foreach (var nd in nodes)
            {
                if (nd.IsOnPossition(x, y))
                    return false;
            }
            return true;
        }

        private bool IsNodeOnTarget(ConsoleNode node)
        {
            if (node.X == target.X && node.Y == target.Y)
                return true;
            return false;
        }

        private void RandomPlacement(List<ConsoleNode> nodes)
        {
            int x = 0;
            int y = 0;
            foreach (var node in nodes)
            {
                do
                {
                    x = rnd.Next(gameField.X, gameField.Width + gameField.X);
                    y = rnd.Next(gameField.Y, gameField.Height + gameField.Y);

                } while (!IsPositionFree(x, y));
                node.X = x;
                node.Y = y;
            }
        }

        private Position CheckPosition(int x, int y)
        {
            if (!IsPositionFree(x, y))
                return Position.Node;
            if (!gameField.IsOnField(x, y))
                return Position.Border;
            return Position.Free;
        }



        private void MoveNodeLeft(object sender, EventArgs e)
        {
            dir = MoveDirectionNode.Left;
        }

        private void MoveNodeRight(object sender, EventArgs e)
        {
            dir = MoveDirectionNode.Right;
        }

        private void MoveNodeUp(object sender, EventArgs e)
        {
            dir = MoveDirectionNode.Up;
        }

        private void MoveNodeDown(object sender, EventArgs e)
        {
            dir = MoveDirectionNode.Down;
        }

        public void ConstantMove(ConsoleNode node, Func<int, int, Position> positionStatus, MoveDirectionNode dir )
        {
            if (dir == MoveDirectionNode.Down)
            {
                if (positionStatus(node.X, node.Y + 1) == Position.Free)
                    node.MoveDown();
            }

            else if (dir == MoveDirectionNode.Up)
            {
                if (positionStatus(node.X, node.Y - 1) == Position.Free)
                    node.MoveUp();
            }

            else if (dir == MoveDirectionNode.Left)
            {
                if (positionStatus(node.X - 1, node.Y) == Position.Free)
                    node.MoveLeft();
            }

            else if (dir == MoveDirectionNode.Right)
            {
                if (positionStatus(node.X + 1, node.Y) == Position.Free)
                    node.MoveRight();
            }
        }

        public void SnakeListMove(List<ConsoleNode> nodes)
        {
            for (int i = nodes.Count - 1; i > 0; i--)
            {
                nodes[i].X = nodes[i - 1].X;
                nodes[i].Y = nodes[i - 1].Y;
                nodes[i].NodeSymbol = '*';
                nodes[i].NodeColor = ConsoleColor.White;
            }

        }
    }

    public enum Position
    {
        Node,
        Border,
        Free
    }
    public enum MoveDirectionNode
    {
        Left,
        Right,
        Up,
        Down
    }






    //private void MoveNodeRandomly(ConsoleNode node)
    //{
    //     int randomMove = rnd.Next(1, 5);
    //     switch (randomMove)
    //     {
    //         case 1:
    //             {
    //                 //MoveUp
    //                 if (IsPositionFree(node.X, node.Y - 1) &&
    //                     gameField.IsOnField(node.X, node.Y - 1))
    //                     node.MoveUp();
    //             }
    //             break;

    //         case 2:
    //             {
    //                 //MoveDown
    //                 if (IsPositionFree(node.X, node.Y + 1) &&
    //                     gameField.IsOnField(node.X, node.Y + 1))
    //                     node.MoveDown();
    //             }
    //             break;

    //         case 3:
    //             {
    //                 //MoveLeft
    //                 if (IsPositionFree(node.X - 1, node.Y) &&
    //                     gameField.IsOnField(node.X - 1, node.Y))
    //                     node.MoveLeft();
    //             }
    //             break;

    //         case 4:
    //             {
    //                 //MoveRight
    //                 if (IsPositionFree(node.X + 1, node.Y) &&
    //                     gameField.IsOnField(node.X + 1, node.Y))
    //                     node.MoveRight();
    //             }
    //             break;
    //     }
    //}
}
